﻿using Kang.ExtendMethod;
using Flurl;
using Flurl.Http;
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Data;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Windows;
using System.Security.Policy;
using System.Net;
using System.Threading.Tasks;
using System.IO;
using System.Reflection;

namespace Kang.Test.Framework.WPF
{
    /// <summary>
    /// App.xaml 的交互逻辑
    /// </summary>
    public partial class App : Application
    {
        private static readonly char[] chars = new char[33]
        {
            '0',
            '1',
            '2',
            '3',
            '4',
            '5',
            '6',
            '7',
            '8',
            '9',
            'a',
            'b',
            'c',
            'd',
            'e',
            'f',
            'g',
            'h',
            'j',
            'k',
            'm',
            'n',
            'p',
            'q',
            'r',
            's',
            't',
            'u',
            'v',
            'w',
            'x',
            'y',
            'z',
        };
        public static double ChunkSize = 1024 * 1024 * 10.0;
        public static string AppName => "大伽病理";
        public static string AppId => "2xB8M87O496W5dI7";
        public static string AppKey => "daka";
        public static string AppSecret => "a8c67988571f416584a6ed1845e527e5";
        // 服务器地址
        public static string AppHost => "https://scs.incell.cn/";
        // 获取临时token GET
        public static string ApiTempToken => "/api/auth/token";
        // 获取切片ID POST
        public static string ApiGetSliceId => "/api/storage/slice";
        // 检测分片是否上传完成 GET
        public static string ApiCheckSliceChunk => "/api/storage/slice/{id}/chunk";
        // 上传分片文件 POST
        public static string ApiUploadSliceChunk => "/api/storage/slice/{id}/chunk";
        // 获取切片解析Token GET
        public static string ApiGetSliceToken => "/api/cloud/slice/token";

        protected override void OnStartup(StartupEventArgs e)
        {
            FlurlHttp.Configure(settings =>
            {
                settings.Timeout = TimeSpan.FromSeconds(1);
            });

            base.OnStartup(e);
        }

        public static string Sign(out long timestamp, out string nonce)
        {
            var codes = chars.GetRandomItems(6).Select(x => $"{x}").ToList();
            nonce = string.Join("", codes);
            timestamp = DateTime.Now.GetTimeStamp();
            var buffer = Encoding.UTF8.GetBytes($"{AppId}{timestamp}{nonce}{AppSecret}");
            var data = SHA1.Create().ComputeHash(buffer);

            StringBuilder sub = new StringBuilder();
            foreach (var t in data)
            {
                sub.Append(t.ToString("X2"));
            }
            return sub.ToString();
        }

        public static IFlurlRequest Request(string Api)
        {
            long t = 0;
            string nonce = string.Empty;
            string sign = Sign(out t, out nonce);
            if (ApiTempToken.Equals(Api))
            {
                return AppHost.AppendPathSegment(Api)
                    .AllowAnyHttpStatus()
                    .WithHeaders(new 
                    { 
                        appId = AppId,
                        timestamp = t,
                        nonce = nonce,
                        sign = sign 
                    });
            }
            else
            {
                return AppHost.AppendPathSegment(Api)
                    .AllowAnyHttpStatus()
                    .WithHeaders(new 
                    { 
                        appId = AppId, 
                        timestamp = t, 
                        nonce = nonce, 
                        sign = sign, 
                        Authorization = TempToken 
                    });
            }
        }

        private static string _tempToken = Request(ApiTempToken).WithTimeout(1).GetAsync().ReceiveJson<Response<TempTokenDto>>()?.Result?.Data?.Token;
        public static string TempToken
        {
            get 
            {
                return _tempToken;
            }
        }

        public static Task<Response> SliceId(string filename, long filesize, string filepath)
        {
            var result = Request(ApiGetSliceId)
                .PostJsonAsync(new 
                { 
                    fileName = filename, 
                    fileSize = filesize, 
                    filePath = filepath, 
                    files = new List<string>() 
                })
                .ReceiveJson<Response>();
            return result;
        }

        public static string SliceFilePath(string filename)
        {
            return Path.Combine("DakaPath", "Slices", filename);
        }

        public static Task<Response> CheckSliceChunk(string filename, string id, int totalChunks, int chunkNumber, long chunkSize, long currentChunkSize, long totalSize)
        {
            var result = Request(ApiCheckSliceChunk.Replace("{id}", id))
                .SetQueryParams(new
                {
                    filename = filename,
                    totalChunks = totalChunks,
                    totalSize = totalSize,
                    currentChunkSize = currentChunkSize,
                    chunkSize = chunkSize,
                    chunkNumber = chunkNumber,
                })
                .GetAsync()
                .ReceiveJson<Response>();
            return result;
        }

        public static Task<Response> UploadSliceChunk(string filepath, string id, int totalChunks, int chunkNumber, long chunkSize, long currentChunkSize, long totalSize, Stream ms)
        {
            var filename = Path.GetFileName(filepath);
            var datas = new byte[(int)App.ChunkSize];
            using (FileStream fs = new FileStream(filepath, FileMode.Open, FileAccess.Read))
            {
                fs.Position = (int)App.ChunkSize * (chunkNumber - 1);
                fs.Read(datas, 0, (int)App.ChunkSize);
                using (FileStream ws = new FileStream($"{id}.{chunkNumber}", FileMode.Create, FileAccess.Write))
                {
                    ws.Write(datas, 0, datas.Length);
                    ws.Flush();
                }
            }
            var result = Request(ApiUploadSliceChunk.Replace("{id}", id))
                .WithTimeout(TimeSpan.FromMinutes(10))
                .OnError(e =>
                {
                    Console.WriteLine(e);
                })
                .SetQueryParams(new
                {
                    filename = filename,
                    totalChunks = totalChunks,
                    totalSize = totalSize,
                    currentChunkSize = currentChunkSize,
                    chunkSize = chunkSize,
                    chunkNumber = chunkNumber,
                })
                .PostMultipartAsync(c =>
                {
                    c.AddFile("file", ms, filename);
                })
                .ReceiveJson<Response>();
            return result;
        }

        public static Task<Response<List<SliceTokenDto>>> GetSliceReadToken(string id)
        {
            var result = Request(ApiGetSliceToken)
                .SetQueryParams(new
                {
                    id = id
                })
                .GetAsync()
                .ReceiveJson<Response<List<SliceTokenDto>>>();
            return result;
        }
    }
}
